﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CILtoNative
{
    internal class MethodEmitter
    {
        private static Stack<object> ObjStack = new Stack<object>();
        private static object LocalVar0 = null;
        private static object LocalVar1 = null;
        private static object LocalVar2 = null;
        private static object LocalVar3 = null;

        public static List<string> UnpluggedMethods = new List<string>();

        public static string GetNativeMethod(string Input, PlugManager pManager)
        {
            string CodeLine = StripOpNumber(Input);
            if (CodeLine.StartsWith("ldstr"))
            {
                ObjStack.Push(GetStrFromLDSTR(CodeLine));
            }
            else if (CodeLine.StartsWith("stloc.0"))
            {
                LocalVar0 = ObjStack.Pop();
            }
            else if (CodeLine.StartsWith("stloc.1"))
            {
                LocalVar1 = ObjStack.Pop();
            }
            else if (CodeLine.StartsWith("stloc.2"))
            {
                LocalVar2 = ObjStack.Pop();
            }
            else if (CodeLine.StartsWith("stloc.3"))
            {
                LocalVar3 = ObjStack.Pop();
            }
            else if (CodeLine.StartsWith("ldloc.0"))
            {
                ObjStack.Push(LocalVar0);
                LocalVar0 = null;
            }
            else if (CodeLine.StartsWith("ldloc.1"))
            {
                ObjStack.Push(LocalVar1);
                LocalVar1 = null;
            }
            else if (CodeLine.StartsWith("ldloc.2"))
            {
                ObjStack.Push(LocalVar2);
                LocalVar2 = null;
            }
            else if (CodeLine.StartsWith("ldloc.3"))
            {
                ObjStack.Push(LocalVar3);
                LocalVar3 = null;
            }
            else if (CodeLine.StartsWith("ldc.i4.s"))
            {
                ObjStack.Push(Convert.ToInt32(CodeLine.Substring(9)));
            }
            else if (CodeLine.StartsWith("ldc.i4.0"))
            {
                ObjStack.Push(0);
            }
            else if (CodeLine.StartsWith("ldc.i4.1"))
            {
                ObjStack.Push(1);
            }
            else if (CodeLine.StartsWith("ldc.i4.2"))
            {
                ObjStack.Push(2);
            }
            else if (CodeLine.StartsWith("ldc.i4.3"))
            {
                ObjStack.Push(3);
            }
            else if (CodeLine.StartsWith("ldc.i4.4"))
            {
                ObjStack.Push(4);
            }
            else if (CodeLine.StartsWith("ldc.i4.5"))
            {
                ObjStack.Push(5);
            }
            else if (CodeLine.StartsWith("ldc.i4.6"))
            {
                ObjStack.Push(6);
            }
            else if (CodeLine.StartsWith("ldc.i4.7"))
            {
                ObjStack.Push(7);
            }
            else if (CodeLine.StartsWith("ldc.i4.8"))
            {
                ObjStack.Push(8);
            }
            else if (CodeLine.StartsWith("ldnull"))
            {
                ObjStack.Push(null);
            }
            else if (CodeLine.StartsWith("call"))
            {
                string CodeCall = CodeLine.Substring(5);
                int ArgsNeeded = pManager.GetArgsNeeded(CodeCall);
                if (ArgsNeeded == -1)
                {
                    ConsoleHelper.ErrorLine("Plug not found.");
                    UnpluggedMethods.Add(CodeCall);
                    return string.Empty;
                }
                else
                {
                    List<object> Args = new List<object>();
                    for (int i = 0; i < ArgsNeeded; i++)
                    {
                        Args.Add(ObjStack.Peek());
                    }
                    return pManager.PlugUpCode(CodeCall, Args);
                }
            }
            return string.Empty;
        }

        private static string StripOpNumber(string Input)
        {
            return Input.Substring(Input.IndexOf(":") + 2);
        }

        private static string GetStrFromLDSTR(string Input)
        {
            int StartIndex = Input.IndexOf("\"") + 1;
            int EndIndex = Input.LastIndexOf("\"");
            return Input.Substring(StartIndex, EndIndex - StartIndex);
        }
    }
}
